/**
 * Token管理器 - 通用模板
 * 适用于Vue3 + Element Plus项目
 * 
 * 功能特性：
 * - JWT token解析和验证
 * - 本地过期时间检测
 * - 服务器端token验证
 * - 自动过期处理
 * - 定时检查机制
 * - 提前警告提醒
 * 
 * @author Your Name
 * @version 1.0.0
 */

import { ElMessage } from 'element-plus'
import router from '@/router'

class TokenManager {
  constructor(options = {}) {
    // 配置项
    this.config = {
      tokenKey: 'token',
      userInfoKey: 'userInfo',
      warningThreshold: 5 * 60, // 5分钟警告阈值
      checkFrequency: 5 * 60 * 1000, // 5分钟检查频率
      apiEndpoint: '/common/login/info', // token验证接口
      loginPath: '/login', // 登录页面路径
      ...options
    }

    // 状态
    this.checkInterval = null
    this.isChecking = false
    this.isRedirecting = false
  }

  /**
   * 获取本地存储的token
   */
  getToken() {
    return localStorage.getItem(this.config.tokenKey)
  }

  /**
   * 设置token到本地存储
   */
  setToken(token) {
    localStorage.setItem(this.config.tokenKey, token)
  }

  /**
   * 清除所有用户数据
   */
  clearUserData() {
    localStorage.removeItem(this.config.tokenKey)
    localStorage.removeItem(this.config.userInfoKey)
    try {
      sessionStorage.removeItem('visitedTabs')
    } catch (e) {
      // 忽略错误
    }
  }

  /**
   * 解析JWT token获取payload
   */
  parseToken(token) {
    try {
      if (!token || typeof token !== 'string') {
        throw new Error('Token无效')
      }
      
      const parts = token.split('.')
      if (parts.length !== 3) {
        throw new Error('Token格式无效')
      }
      
      const base64Url = parts[1]
      if (!base64Url) {
        throw new Error('Token payload缺失')
      }
      
      const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
      const jsonPayload = decodeURIComponent(
        atob(base64)
          .split('')
          .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
          .join('')
      )
      return JSON.parse(jsonPayload)
    } catch (error) {
      console.error('Token解析失败:', error)
      return null
    }
  }

  /**
   * 检查token是否过期（基于exp字段）
   */
  isTokenExpired(token) {
    if (!token) return { expired: true, timeLeft: 0, timeLeftMinutes: 0, payload: null }

    const payload = this.parseToken(token)
    if (!payload || !payload.exp) return { expired: true, timeLeft: 0, timeLeftMinutes: 0, payload: null }

    const currentTime = Math.floor(Date.now() / 1000)
    const expireTime = payload.exp
    const timeLeft = expireTime - currentTime

    return {
      expired: timeLeft <= 0,
      timeLeft: timeLeft,
      timeLeftMinutes: Math.floor(timeLeft / 60),
      payload: payload
    }
  }

  /**
   * 检查token是否即将过期
   */
  isTokenExpiringSoon(token) {
    const result = this.isTokenExpired(token)
    return {
      ...result,
      expiringSoon: result.timeLeft < this.config.warningThreshold && result.timeLeft > 0
    }
  }

  /**
   * 通过API验证token有效性
   */
  async validateTokenWithServer() {
    const token = this.getToken()
    if (!token) return false

    try {
      const response = await fetch(this.config.apiEndpoint, {
        method: 'GET',
        headers: {
          'token': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      })

      if (response.ok) {
        return true
      } else {
        this.handleTokenInvalid('服务器验证失败')
        return false
      }
    } catch (error) {
      console.error('Token服务器验证失败:', error)
      this.handleTokenInvalid('网络验证失败')
      return false
    }
  }

  /**
   * 处理token无效的情况
   */
  handleTokenInvalid(reason = 'Token无效') {
    if (this.isRedirecting) return
    
    this.isRedirecting = true
    console.log(`Token无效: ${reason}`)
    this.clearUserData()
    ElMessage.error('登录已过期，请重新登录')
    router.push(this.config.loginPath)
    
    setTimeout(() => {
      this.isRedirecting = false
    }, 1000)
  }

  /**
   * 显示过期警告
   */
  showExpiryWarning(minutes) {
    ElMessage.warning(`登录即将过期，还有${minutes}分钟，请及时保存工作`)
  }

  /**
   * 本地token检查（不发送网络请求）
   */
  checkLocalToken() {
    const token = this.getToken()
    if (!token) return false

    const result = this.isTokenExpiringSoon(token)

    if (result.expired) {
      this.handleTokenInvalid('Token已过期')
      return false
    }

    if (result.expiringSoon) {
      this.showExpiryWarning(result.timeLeftMinutes)
    }

    return true
  }

  /**
   * 完整的token检查（本地 + 服务器）
   */
  async checkToken() {
    if (this.isChecking) return
    this.isChecking = true

    try {
      // 先检查本地过期时间
      if (!this.checkLocalToken()) {
        return false
      }

      // 再通过服务器验证
      const isValid = await this.validateTokenWithServer()
      return isValid
    } finally {
      this.isChecking = false
    }
  }

  /**
   * 启动定时检查
   */
  startPeriodicCheck() {
    if (this.checkInterval) return

    this.checkInterval = setInterval(async () => {
      await this.checkToken()
    }, this.config.checkFrequency)

    console.log('Token定时检查已启动')
  }

  /**
   * 停止定时检查
   */
  stopPeriodicCheck() {
    if (this.checkInterval) {
      clearInterval(this.checkInterval)
      this.checkInterval = null
      console.log('Token定时检查已停止')
    }
  }

  /**
   * 登录成功后初始化
   */
  onLoginSuccess(token) {
    this.setToken(token)
    this.startPeriodicCheck()
    // 立即检查一次
    this.checkToken()
  }

  /**
   * 退出登录时清理
   */
  onLogout() {
    this.stopPeriodicCheck()
    this.clearUserData()
  }

  /**
   * 应用启动时初始化
   */
  onAppStart() {
    const token = this.getToken()
    if (token) {
      this.startPeriodicCheck()
      // 立即检查一次
      this.checkToken()
    }
  }

  /**
   * 获取token信息（调试用）
   */
  getTokenInfo() {
    const token = this.getToken()
    if (!token) return null

    const result = this.isTokenExpired(token)
    return {
      token: token.substring(0, 20) + '...',
      expired: result.expired,
      timeLeft: result.timeLeft,
      timeLeftMinutes: result.timeLeftMinutes,
      payload: result.payload
    }
  }

  /**
   * 更新配置
   */
  updateConfig(newConfig) {
    this.config = { ...this.config, ...newConfig }
  }

  /**
   * 销毁实例
   */
  destroy() {
    this.stopPeriodicCheck()
    this.clearUserData()
  }
}

// 创建默认实例
const tokenManager = new TokenManager()

// 导出类和实例
export default tokenManager
export { TokenManager }